package top.codedance.iotp.converter.service.master;

import top.codedance.iotp.converter.ConverterApplication;
import top.codedance.iotp.converter.bean.MasterConnectParam;
import top.codedance.iotp.common.util.StringUtils;
import top.codedance.iotp.converter.service.slave.Slave;
import org.apache.log4j.Logger;

import java.lang.reflect.Constructor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public abstract class AbstractMaster implements Master {
    private static Logger logger = ConverterApplication.getLogger(AbstractMaster.class);
    protected MasterConnectParam param;
    protected static String type = "Serial";
    protected static final String pkg = "top.codedance.iotp.converter.service.master";
    protected static Master m = null;
    private static Lock lock = new ReentrantLock();

    public AbstractMaster(MasterConnectParam mcp){
        this.param = mcp;
    }

    @Override
    public void run() {
        init();
    }

    public static Master getInstance(MasterConnectParam mcp){
        type = StringUtils.firstCharToUperCase(mcp.getType());
        if(m == null)
        synchronized (AbstractMaster.class){
            if(m == null){
                String clazzType = pkg + "." + type + "Master";
                try {
                    Constructor<?> constructor = Class.forName(clazzType).getConstructor(MasterConnectParam.class);
                    m = (Master) constructor.newInstance(mcp);
                }catch (Exception e){
                    logger.info("Master port is init fail, system is shutdown.");
                    System.exit(0);
                }
            }
        }
        return m;
    }

    /**
     * 发送数据
     * @param data
     */
    @Override
    public abstract void send(Slave slave, byte[] data);

    /**
     * 初始化服务
     */
    @Override
    public abstract void init();

    /**
     * 销毁服务
     */
    @Override
    public abstract void destory();

    /**
     * 发送数据
     * @param data
     */
    @Override
    public abstract byte[] request(byte[] data);

    @Override
    public abstract void recover(byte[] data);

    @Override
    public abstract int readHoldingRegister(int offset);

    @Override
    public abstract int[] readHoldingRegisterRange(int offset, int quantity);

    @Override
    public abstract void writeHoldingRegister(int offset, int value);

    @Override
    public abstract void writeHoldingRegisterRange(int offset, int[] range);

    @Override
    public abstract boolean[] readCoilRange(int offset, int quantity);

    @Override
    public abstract void writeCoil(int offset, boolean value);

    @Override
    public abstract void writeCoilRange(int offset, boolean[] range);

    @Override
    public abstract byte[] request(int offset, int quantity);

    /**
     * 是否是串口
     * @return
     */
    @Override
    public boolean isSerial(){
        return !this.param.isModbus();
    }

    /**
     * 是否是modbus协议
     * @return
     */
    @Override
    public boolean isModbus(){
        return this.param.isModbus();
    }

    @Override
    public boolean tryLock(){
        boolean result = false;
        try {
            result = lock.tryLock(10, TimeUnit.SECONDS);
        }catch (Exception e){
            logger.debug(e.getMessage());
        }
        return result;
    }

    @Override
    public void release(){
        lock.unlock();
    }
}
